package felix.rule.service.actors.chain;

import felix.actor.core.TActorRef;
import felix.actor.core.msg.TActorMsg;
import felix.rule.data.msg.RuleChain;
import felix.rule.service.RuleChainService;
import felix.rule.service.actors.ActorSystemContext;
import felix.rule.service.actors.ContextAwareActor;
import felix.rule.service.actors.TEntityActorId;
import felix.rule.service.impl.DefaultActorService;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.util.function.Function;

/**
 * @author Felix
 * @date 2020/8/24
 */
@Slf4j
public abstract class RuleChainManagerActor extends ContextAwareActor {

    protected final String ruleId;
    private final RuleChainService ruleChainService;
    @Getter
    protected RuleChain rootChain;
    @Getter
    protected TActorRef rootChainActor;

    public RuleChainManagerActor(ActorSystemContext systemContext, String ruleId) {
        super(systemContext);
        this.ruleId = ruleId;
        this.ruleChainService = systemContext.getRuleChainService();
    }

    protected void initRuleChains() {
        RuleChain ruleChain = ruleChainService.findRuleChain(ruleId);
        if (ruleChain != null) {
            String ruleId = ruleChain.getRuleId();
            log.debug("[{}] Creating rule chain actor", ruleId);
            TActorRef actorRef = getOrCreateActor(ruleId, id -> ruleChain);
            visit(ruleChain, actorRef);
            log.debug("[{}] Rule Chain actor created.", ruleId);
        }
    }

    protected void visit(RuleChain entity, TActorRef actorRef) {
        if (entity != null) {
            rootChain = entity;
            rootChainActor = actorRef;
        }
    }

    protected TActorRef getOrCreateActor(String ruleChainId) {
        return getOrCreateActor(ruleChainId, ruleChainService::findRuleChainById);
    }

    protected TActorRef getOrCreateActor(String ruleChainId, Function<String, RuleChain> provider) {
        if (provider == null) {
            return null;
        }
        return ctx.getOrCreateChildActor(new TEntityActorId(ruleChainId, RuleChainActor.class.getSimpleName()),
                () -> DefaultActorService.RULE_DISPATCHER_NAME,
                () -> {
                    RuleChain ruleChain = provider.apply(ruleChainId);
                    return new RuleChainActor.ActorCreator(systemContext, ruleId, ruleChain);
                });
    }

    protected TActorRef getEntityActorRef(String entityId) {
        return getOrCreateActor(entityId);
    }

    protected void broadcast(TActorMsg msg) {
//        ctx.broadcastToChildren(msg, new TbEntityTypeActorIdPredicate(EntityType.RULE_CHAIN));
    }
}
